﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Crude.VisualStudioAddin.ViewModels;
using Crude.Common;
using Crude.Core;
using Crude.Core.Repository;
using EnvDTE;

namespace Crude.VisualStudioAddin.Forms
{
    public partial class ProjectReferencesForm : Form
    {
        Crude.Core.Project m_crudeProject;

        VSLangProj.VSProject m_vsProject;
        EnvDTE80.DTE2 m_applicationObject;
        EnvDTE.Project m_project;

        IList<ProjectReferenceViewModel> m_deletedRows = new List<ProjectReferenceViewModel>();
        IList<ProjectReferenceViewModel> m_newReferences =  new List<ProjectReferenceViewModel>();

        IList<ProjectReferenceViewModel> m_referenceViewModels;

        public ProjectReferencesForm(EnvDTE80.DTE2 applicationObject, EnvDTE.Project project)
        {
            InitializeComponent();
            m_crudeProject = new Core.Project(project.FullName);
            m_vsProject = (VSLangProj.VSProject)project.Object;
            m_project = project;
            m_applicationObject = applicationObject;
        }

        private void ProjectReferencesForm_Load(object sender, EventArgs e)
        {
            ProjectObjectModel pom = new ProjectObjectModelLoader(m_crudeProject.PomFilePath).Load();

            m_referenceViewModels = new List<ProjectReferenceViewModel>();

            HashSet<string> frameworkAssemblies = FrameworkUtility.GetFrameworkAssemblies();

            IRemoteRepository remoteRepository = new RemoteRepositoryBuilder().Build();

            foreach (VSLangProj.Reference vsReference in m_vsProject.References)
            {
                if (!frameworkAssemblies.Contains(vsReference.Name.ToLower()))
                {
                    ProjectReferenceViewModel projectReferenceViewModel = new ProjectReferenceViewModel();
                    projectReferenceViewModel.Name = vsReference.Name;
                    projectReferenceViewModel.Version = vsReference.Version;

                    ProjectDependency projectDependency = (
                        from dependency in pom.Dependencies
                        where dependency.Name == vsReference.Name
                        select dependency).FirstOrDefault();

                    if (projectDependency != null)
                    {
                        projectReferenceViewModel.OriginalCrudeReference = projectReferenceViewModel.CrudeReference = true;
                        projectReferenceViewModel.Version = projectDependency.Version;
                    }

                    IList<ProjectObjectModel> versions = remoteRepository.GetProjectAvailableVersions(vsReference.Name);


                    ProjectObjectModel currentReferencePom = remoteRepository.GetProjectObjectModel(projectDependency);

                    if (currentReferencePom != null)
                    {
                        projectReferenceViewModel.Description = currentReferencePom.Description;
                    }

                    if (versions.Count > 0)
                    {                                               

                        projectReferenceViewModel.IsCrudeAvailable = true;
                        projectReferenceViewModel.AvailableVersions = versions;
                    }

                    m_referenceViewModels.Add(projectReferenceViewModel);
                }
            }

            dataGridView1.AutoGenerateColumns = false;
            SetDataSource();
        }

        private void SetDataSource()
        {
            dataGridView1.DataSource = m_referenceViewModels;

            foreach (DataGridViewRow row in dataGridView1.Rows)
            {
                ProjectReferenceViewModel projectReferenceViewModel = (ProjectReferenceViewModel)row.DataBoundItem;

                if (!projectReferenceViewModel.CrudeReference && !projectReferenceViewModel.IsCrudeAvailable)
                {
                    row.ReadOnly = true;
                    row.DefaultCellStyle.BackColor = SystemColors.Control;
                }
            }
        }

        private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {
            if (e.RowIndex >= 0)
            {
                ProjectReferenceViewModel projectReferenceViewModel = (ProjectReferenceViewModel)
                    dataGridView1.Rows[e.RowIndex].DataBoundItem;

                if (e.ColumnIndex == m_version.Index && projectReferenceViewModel.IsCrudeAvailable &&
                    projectReferenceViewModel.CrudeReference)
                {
                    SelectVersionForm selectVersionForm = new SelectVersionForm(projectReferenceViewModel.AvailableVersions,
                        projectReferenceViewModel.Version);
                    selectVersionForm.Location = new Point(Cursor.Position.X, Cursor.Position.Y);

                    if (selectVersionForm.ShowDialog() == DialogResult.OK)
                    {
                        projectReferenceViewModel.Version = selectVersionForm.CurrentVersion;
                    }
                }
                else if (e.ColumnIndex == m_crudeStatus.Index &&
                    (projectReferenceViewModel.IsCrudeAvailable || projectReferenceViewModel.CrudeReference))
                {
                    if (projectReferenceViewModel.CrudeReference)
                    {
                        projectReferenceViewModel.CrudeReference = false;
                    }
                    else
                    {
                        projectReferenceViewModel.CrudeReference = true;
                    }

                    dataGridView1.Refresh();
                }
            }
        }

        private void m_okButton_Click(object sender, EventArgs e)
        {
            ProjectObjectModel pom = new ProjectObjectModelLoader(m_crudeProject.PomFilePath).Load();

            foreach (ProjectReferenceViewModel viewModel in m_referenceViewModels)
            {
                if (viewModel.CrudeReference && !viewModel.OriginalCrudeReference)
                {
                    ProjectDependency projectDependency = new ProjectDependency();
                    projectDependency.Name = viewModel.Name;
                    projectDependency.Version = viewModel.Version;
                    pom.Dependencies.Add(projectDependency);
                }
                else if (viewModel.CrudeReference)
                {
                    ProjectDependency projectDependency =
                        (from dependency in pom.Dependencies
                         where dependency.Name == viewModel.Name
                         select dependency).First();

                    projectDependency.Version = viewModel.Version;
                }
                else if (!viewModel.CrudeReference && viewModel.OriginalCrudeReference)
                {
                    ProjectDependency projectDependency =
                        (from dependency in pom.Dependencies
                         where dependency.Name == viewModel.Name
                         select dependency).First();

                    pom.Dependencies.Remove(projectDependency);
                }
            }

            IRemoteRepository remoteRepository = new RemoteRepositoryBuilder().Build();
            LocalRepository localRepository = new LocalRepositoryBuilder().Build();

            foreach (ProjectReferenceViewModel viewModel in m_newReferences)
	        {
                ProjectDependency projectDependency = new ProjectDependency
                {
                    Name = viewModel.Name,
                    Version = viewModel.Version
                };

                ProjectObjectModel dependencyPom = localRepository.GetProjectObjectModel(projectDependency);

                if (dependencyPom == null)
                {
                    dependencyPom = remoteRepository.GetProjectObjectModel(projectDependency);

                    if (dependencyPom != null)
                    {
                        remoteRepository.DownloadAssmebly(dependencyPom);
                    }
                }

                if (dependencyPom != null)
                {
                    string assemblyPath = Path.Combine(localRepository.GetPomDirectory(dependencyPom),
                                                       dependencyPom.MainOutputFile);                        

                    FileInfo fileInfo = new FileInfo(m_project.FullName);

                    string outputPath = m_project.ConfigurationManager.ActiveConfiguration.Properties.Item("OutputPath").Value.ToString();

                    string destinationPath = Path.Combine(fileInfo.DirectoryName, outputPath,
                                                          dependencyPom.MainOutputFile);

                    if (!File.Exists(destinationPath))
                    {
                        File.Copy(assemblyPath, destinationPath);
                    }

                    m_vsProject.References.Add(dependencyPom.MainOutputFile);
                }		        
	        }

            foreach (ProjectReferenceViewModel viewModel in m_deletedRows)
            {
                ProjectDependency projectDependency =
                        (from dependency in pom.Dependencies
                         where dependency.Name == viewModel.Name
                         select dependency).FirstOrDefault();

                if (projectDependency != null)
                {
                    pom.Dependencies.Remove(projectDependency);
                }

                m_vsProject.References.Item(viewModel.Name).Remove();
            }

            m_project.Save();

            if (m_applicationObject.SourceControl.IsItemUnderSCC(m_crudeProject.PomFilePath) &&
                !m_applicationObject.SourceControl.IsItemCheckedOut(m_crudeProject.PomFilePath))
            {
                m_applicationObject.SourceControl.CheckOutItem(m_crudeProject.PomFilePath);
            }

            new ProjectObjectModelSaver().Save(m_crudeProject.PomFilePath, pom);

            Close();
        }

        private void m_cancelButton_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void m_deleteButton_Click(object sender, EventArgs e)
        {
            if (dataGridView1.CurrentRow != null && dataGridView1.CurrentRow.DataBoundItem is ProjectReferenceViewModel)
            {
                ProjectReferenceViewModel projectReferenceViewModel = (ProjectReferenceViewModel)
                       dataGridView1.CurrentRow.DataBoundItem;

                if (MessageBox.Show("Are you sure you want to delete the reference?",
                    "Crude", MessageBoxButtons.YesNo) == System.Windows.Forms.DialogResult.Yes)
                {
                    m_referenceViewModels.Remove(projectReferenceViewModel);

                    m_deletedRows.Add(projectReferenceViewModel);

                    dataGridView1.DataSource = null;
                    SetDataSource();
                }
            }
        }

        private void m_addButton_Click(object sender, EventArgs e)
        {
            AddCrudeReferenceForm addCrudeReferenceForm =
                new AddCrudeReferenceForm(m_crudeProject.AssemblyName,
                    m_referenceViewModels.Select(r => r.Name).ToList());
            if (addCrudeReferenceForm.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                IRemoteRepository remoteRepository = new RemoteRepositoryBuilder().Build();

                foreach (string name in addCrudeReferenceForm.SelectedReferences)
                {
                    ProjectReferenceViewModel projectReferenceViewModel =
                        new ProjectReferenceViewModel();

                    projectReferenceViewModel.Name = name;
                    projectReferenceViewModel.Version = "*";
                    projectReferenceViewModel.OriginalCrudeReference = false;
                    projectReferenceViewModel.CrudeReference = true;
                    projectReferenceViewModel.IsCrudeAvailable = true;
                    projectReferenceViewModel.AvailableVersions = remoteRepository.GetProjectAvailableVersions(name);

                    m_referenceViewModels.Add(projectReferenceViewModel);
                    m_newReferences.Add(projectReferenceViewModel);
                }

                dataGridView1.DataSource = null;
                SetDataSource();
            }
        }

    }
}
